using Engine.Graphics;
using SharpDX;
using SharpDX.Direct3D11;
using System;
using System.Windows.Forms;
using System.Windows.Interop;

namespace Engine
{
    public class Engine
    {
        #region Private Fields

        private float gameTime;
        private System.Diagnostics.Stopwatch GameTimeStopWatch;
        private System.Windows.Window globalWpfModelViewerWindow1;

        private Graphics.Graphic grafic;

        private Input.KeyboardInput keyboard;

        private Input.MouseInput mouse;

        private RenderText renderText;

        private Color4 standardTextColor = new Color4()
        {
            Alpha = 1.0f,
            Red = 1.0f,
            Green = 0.0f,
            Blue = 0.0f
        };

        private Viewport topRender;

        private Viewport viewComplete;

        #endregion Private Fields

        #region Public Constructors

        public Engine(System.Windows.Window wpfWindow, HwndSource hwndSource, Camera.Camera camera)
            : this(hwndSource.Handle)
        {
            this.globalWpfModelViewerWindow1 = wpfWindow;
            this.grafic = new global::Engine.Graphics.Graphic(hwndSource.Handle, (int)wpfWindow.Height, (int)wpfWindow.Width, camera, this);
        }

        public Engine(Panel panelForView, IntPtr handlePointer)
            : this(handlePointer)
        {
            this.viewComplete = new Viewport(0, 0, panelForView.ClientSize.Width, panelForView.ClientSize.Height, 0.0f, 1.0f);

            panelForView.Resize += new EventHandler(panelForView_SizeChanged);

            this.grafic = new global::Engine.Graphics.Graphic(panelForView.Handle, panelForView.ClientSize.Height, panelForView.ClientSize.Width, new Camera.Camera(), this);
            panelForView.Resize += new EventHandler(grafic.SizeChangePanel);

            this.renderText = new Graphics.RenderText(this.Grafic);
        }

        public Engine(IntPtr handlePointer)
        {
            this.topRender = new Viewport(5, 5, 200, 100, 0.0f, 1.0f);
            this.keyboard = new global::Engine.Input.KeyboardInput(handlePointer);
            this.mouse = new global::Engine.Input.MouseInput(handlePointer);
            this.GameTimeStopWatch = new System.Diagnostics.Stopwatch();
            this.GameTimeStopWatch.Start();
        }

        #endregion Public Constructors

        #region Public Properties

        public Camera.Camera Camera
        {
            get { return this.grafic.Camera; }
            set { this.grafic.Camera = value; }
        }

        public Device Device
        {
            get { return this.grafic.Device; }
        }

        /// <summary>
        /// Gametime in seconds.
        /// </summary>
        public float GamaTime
        {
            get { return gameTime; }
            set { gameTime = value; }
        }

        public Graphics.Graphic Grafic
        {
            get { return grafic; }
            set { grafic = value; }
        }

        public Input.KeyboardInput Keyboard
        {
            get { return keyboard; }
            set { keyboard = value; }
        }

        public Input.MouseInput Mouse
        {
            get { return mouse; }
            set { mouse = value; }
        }

        public string RenderText
        {
            set { renderText.SetTextOnScreen(value, 10, 10, this.standardTextColor); }
        }

        #endregion Public Properties

        #region Public Methods

        public void AddShaderManager(ShaderManager shaderManager)
        {
            this.grafic.ShaderManager.Add(shaderManager);
        }

        public void Dispose()
        {
            this.grafic.Dispose();
            this.keyboard.Dispos();
            this.mouse.Dispose();
        }

        public Matrix GetWorldViewProjectionMatrix()
        {
            return grafic.GetWorldViewProjectionMatrix();
        }

        public void GlobalRendering(EnumGlobalMappingMode enumGlobalMappingMode)
        {
            foreach (var item in this.grafic.ShaderManager)
            {
                item.GlobalMapping = enumGlobalMappingMode;
            }
        }

        public void RemoveShaderManager(ShaderManager shaderManager)
        {
            this.grafic.ShaderManager.Remove(shaderManager);
        }

        public void Render()
        {
            grafic.Render();
        }

        public void SetLightDirection(Vector3 lightDirection)
        {
            this.grafic.SetLightDirection(lightDirection);
        }

        public void Update()
        {
            this.gameTime = this.GameTimeStopWatch.ElapsedMilliseconds / 1000.0f;
            keyboard.Update();
            mouse.Update();
            grafic.SetupMatricesAndShaderValues();
        }

        public void Update(System.Drawing.Point MousePositionOnScreen)
        {
            Update();
            grafic.MousePosition = MousePositionOnScreen;
        }

        public void Update(CameraControl cameraControl, System.Drawing.Point MousePositionOnScreen, bool moveCamera)
        {
            Update(MousePositionOnScreen);
            if (moveCamera)
                cameraControl.MoveCamera(Keyboard, Mouse);
        }

        #endregion Public Methods

        #region Private Methods

        private void panelForView_SizeChanged(object sender, EventArgs e)
        {
            Panel panelForView = (Panel)sender;
            this.viewComplete = new Viewport(0, 0, panelForView.ClientSize.Width, panelForView.ClientSize.Height, 0.0f, 1.0f);
        }

        #endregion Private Methods
    }
}